<template>
  <!-- 使用v-show控制面板显隐 -->
  <div class="panel right-panel" :style="{
    width: width + 'px'
  }" v-show="true">
    <!-- 聊天消息区 -->
    <div class="ai-header">AI助手</div>

    <div class="ai-chat">
      <div class="chat-message-wrapper" v-for="msg in chatMessages" :key="msg.id">
        <div :class="['chat-message', 'message-' + msg.type]">
          <strong>{{ msg.type === 'user' ? '你' : 'AI' }}：</strong>
          <pre class="message-content">{{ msg.content }}</pre>
        </div>
      </div>
      <!--    采纳提示或错误提示位置  -->
      <div v-if="streamError === '用户主动终止对话' || streamError === '对话正常结束'" class="user-stopped-prompt-yellow">
        <span>是否采纳：</span>
        <button @click="addToLeft" class="adopt-current-button">采纳</button>
      </div>
      <div v-else-if="streamError" class="stream-error-message"> <!-- 其他错误则显示红色提示 -->
        {{ streamError }}
      </div>
    </div>

    <!-- 修改后的底部输入区域 -->
    <div class="panel-content">
      <div class="ai-input-new">
        <div>

          <el-switch
            v-model="value2"
            class="ml-2"
            style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
          />
          <div class="input-prefix-area">
            <el-select v-model="modelSel" placeholder="模型" size="small"
                       class="compact-model-select">
              <el-option label="DeepSeek" value="deepseek-ai/DeepSeek-V3"
                         :key="'deepseek-ai/DeepSeek-V3'"></el-option>
              <el-option label="通义千问" value="Qwen/Qwen3-8B" :key="'Qwen/Qwen3-8B'"></el-option>
            </el-select>
          </div>
        </div>


        <el-input
          v-model="chatInput"
          type="textarea"
          :autosize="{ minRows: 1, maxRows: 4 }"
          placeholder="输入 Shift + Enter 换行"
          clearable
          ref="inputRef"
          class="main-chat-input"
          @keyup.enter.exact.prevent="isStreaming ? null : toggleStream()"
          :disabled="isStreaming"
        />

        <div class="input-actions-suffix">
          <button @click="clearChatMessages" class="action-button clear-chat-button" title="思维导图" aria-label="思维导图">
            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M3 6s1.5-2 5-2 5 2 5 2"/>
              <path d="M3 10s1.5-2 5-2 5 2 5 2"/>
              <path d="M12 14s1.5-2 5-2 5 2 5 2"/>
              <path d="M12 18s1.5-2 5-2 5 2 5 2"/>
              <rect x="2" y="4" width="7" height="4" rx="1"/>
              <rect x="2" y="12" width="7" height="4" rx="1"/>
              <rect x="15" y="8" width="7" height="4" rx="1"/>
              <rect x="15" y="16" width="7" height="4" rx="1"/>
              <line x1="9" y1="6" x2="12" y2="6"/>
              <line x1="9" y1="14" x2="12" y2="14"/>
              <line x1="12" y1="10" x2="15" y2="10"/>
              <line x1="12" y1="18" x2="15" y2="18"/>
            </svg>
          </button>

          <button @click="clearChatMessages" class="action-button clear-chat-button" title="清空对话" aria-label="清空对话">
            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
              <path d="M17.65 6.35A7.958 7.958 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
            </svg>
          </button>
          <button @click="toggleStream" class="action-button send-button" :class="{ 'streaming': isStreaming }"
                  :title="isStreaming ? '停止对话' : '发送消息'" ref="streamButtonRef" aria-label="发送消息">
            <span v-if="!isStreaming">
              <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
                <path d="M3 19.525V4.475L22.05 12L3 19.525ZM5 17.525L18.05 12L5 6.475V10.5L11 12l-6 1.5v4.025Z"/>
              </svg>
            </span>
            <span v-else>
              <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
                <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM8 9h8v10H8V9zm7.5-5l-1-1h-5l-1 1H5v2h14V4h-3.5z"></path>
              </svg>
            </span>
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {ref, onMounted, nextTick, watch, onUnmounted} from 'vue';
import {currentNodeInfo} from '@/stores/currentNodeStore';
import { aiMessageStore } from '@/stores/aiMessage';
import {useEditorStore} from "@/stores/editStore.ts";

const aiMmgStore = aiMessageStore()
const currentNode = currentNodeInfo()
const editorStore = useEditorStore();

const chatInput = ref('');
const inputRef = ref<any>(null);
const streamButtonRef = ref<HTMLButtonElement | null>(null);
const modelSel = ref('deepseek-ai/DeepSeek-V3');
const isStreaming = ref(false);
const streamError = ref<string | null>(null);
const abortController = ref<AbortController | null>(null);
let currentAiMessageId: string | null = null;


const value2 = ref(false)

interface ChatMessage {
  id: string;
  type: 'user' | 'ai';
  content: string;
}
const props = defineProps({
  width: { type: Number, required: true },
  visible: { type: Boolean, required: true },
  initialMessages: { type: Array as () => string[], default: () => [] }
});
const emit = defineEmits(['close', 'update:isAIOpen', 'messageSent', 'modelChanged']);

const parseInitialMessage = (msgStr: string): { type: 'user' | 'ai', content: string } => {
  const lowerMsgStr = msgStr.toLowerCase();
  let type: 'user' | 'ai' = 'ai';
  let content = msgStr.trim();
  const userPrefixes = ["你：", "user:"];
  const aiPrefixes = ["ai：", "assistant:"];
  for (const prefix of userPrefixes) {
    if (lowerMsgStr.startsWith(prefix)) {
      type = 'user';
      content = msgStr.substring(prefix.length).trim();
      break;
    }
  }
  if (type === 'ai') {
    for (const prefix of aiPrefixes) {
      if (lowerMsgStr.startsWith(prefix)) {
        type = 'ai';
        content = msgStr.substring(prefix.length).trim();
        break;
      }
    }
  }
  return {type, content};
};

const chatMessages = ref<ChatMessage[]>(
  props.initialMessages.map((msgStr, index) => {
    const {type, content} = parseInitialMessage(msgStr);
    return {id: `initial-${index}-${Date.now()}`, type, content};
  })
);

const scrollToBottom = () => {
  nextTick(() => {
    const chatArea = document.querySelector('.ai-chat');
    if (chatArea) {
      chatArea.scrollTop = chatArea.scrollHeight;
    }
  });
};

const updateAiMessageWithStreamData = (data: string) => {
  const aiMessageEntry = chatMessages.value.find(m => m.id === currentAiMessageId);
  if (aiMessageEntry) {
    const formattedData = data.replace(/\\n/g, '\n');
    aiMessageEntry.content += formattedData;
    aiMmgStore.resposeMarkdon = aiMessageEntry.content;
    scrollToBottom();
  }
};

const updateFinalAiMessageWithStatus = (statusMessage: string, isErrorType: boolean) => {
  const aiMessageEntry = chatMessages.value.find(m => m.id === currentAiMessageId);
  const messageToDisplay = `${isErrorType ? '[错误: ' : '['}${statusMessage}${isErrorType ? ']' : ']'}`;
  if (aiMessageEntry) {
    if (aiMessageEntry.content === '' || !aiMessageEntry.content.includes(messageToDisplay)) {
      aiMessageEntry.content += (aiMessageEntry.content.endsWith('\n') || aiMessageEntry.content === '' ? '' : '\n') + messageToDisplay;
    }
  } else if (currentAiMessageId) {
    chatMessages.value.push({id: currentAiMessageId, type: 'ai', content: messageToDisplay});
  } else {
    chatMessages.value.push({id: `ai-status-${Date.now()}`, type: 'ai', content: messageToDisplay});
  }
  scrollToBottom();
};

const clearChatMessages = () => {
  if (isStreaming.value && abortController.value) {
    abortController.value.abort();
  }
  chatMessages.value = [];
  streamError.value = null;
};

const addToLeft = () => {
  if (aiMmgStore.resposeMarkdon) {
    editorStore.insertContext(aiMmgStore.resposeMarkdon);
    if (streamError.value === '用户主动终止对话' || streamError.value === '对话正常结束') {
      streamError.value = null;
    }
  }
};

// handleAdoptContent function seems to be a duplicate of addToLeft, keeping one.
// const handleAdoptContent = () => {
//   const contentToAdopt = aiMmgStore.resposeMarkdon;
//   if (contentToAdopt) {
//     editorStore.insertContext(contentToAdopt);
//   }
//   if (streamError.value === '用户主动终止对话' || streamError.value === '对话正常结束') {
//     streamError.value = null;
//   }
// };


const startStream = async () => {
  const currentcontent = value2.value ? currentNode.nodeMarkdown : ''; // 根据开关状态决定是否包含上下文
  const userInput = chatInput.value.trim();

  if (!userInput) {
    streamError.value = '请输入您的问题。';
    return;
  }

  streamError.value = null;
  isStreaming.value = true;
  abortController.value = new AbortController();
  chatMessages.value.push({id: `user-${Date.now()}`, type: 'user', content: userInput});
  emit('messageSent', userInput);
  currentAiMessageId = `ai-${Date.now()}`;
  chatMessages.value.push({id: currentAiMessageId, type: 'ai', content: ''});
  chatInput.value = '';
  scrollToBottom();

  let doneReadingStream = false;
  let caughtErrorDuringStream: Error | null = null;

  try {
    const streamUrl = `http://localhost:8080/api/chat_t/stream_t`;
    const response = await fetch(streamUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'text/event-stream',
        'satoken': localStorage.getItem("satoken")||""
      },
      body: JSON.stringify({
        message: currentcontent + userInput,
        model: modelSel.value,
      }),
      signal: abortController.value.signal,
    });
    if (!response.ok) {
      let errorData = `请求失败，状态码: ${response.status}`;
      try { const errorJson = await response.json(); errorData = errorJson.detail || errorJson.message || JSON.stringify(errorJson); }
      catch (e) { errorData = (await response.text()) || errorData; }
      throw new Error(errorData);
    }
    if (!response.body) throw new Error('Response body is null.');

    const reader = response.body.getReader();
    const decoder = new TextDecoder('utf-8');
    let accumulatedChunk = '';

    while (!doneReadingStream) {
      try {
        const {value, done} = await reader.read();
        if (value) {
          accumulatedChunk += decoder.decode(value, {stream: true});
          let contentForThisPass = "";
          const doneSignalIndex = accumulatedChunk.indexOf("[DONE]");
          if (doneSignalIndex !== -1) {
            const partBeforeDone = accumulatedChunk.substring(0, doneSignalIndex);
            partBeforeDone.split('\n').forEach(line => {
              const trimmedLine = line.trim();
              if (trimmedLine.startsWith("data:")) contentForThisPass += trimmedLine.substring(5);
            });
            accumulatedChunk = '';
            doneReadingStream = true;
          } else {
            let searchStartIndex = 0;
            while (true) {
              const newlineIndex = accumulatedChunk.indexOf('\n', searchStartIndex);
              if (newlineIndex === -1) break;
              const line = accumulatedChunk.substring(searchStartIndex, newlineIndex).trim();
              if (line.startsWith("data:")) contentForThisPass += line.substring(5);
              searchStartIndex = newlineIndex + 1;
            }
            accumulatedChunk = accumulatedChunk.substring(searchStartIndex);
          }
          if (contentForThisPass) updateAiMessageWithStreamData(contentForThisPass);
        }
        if (done) doneReadingStream = true;
        if (doneReadingStream) {
          if (accumulatedChunk.trim()) {
            let finalContent = "";
            accumulatedChunk.split('\n').forEach(line => {
              const trimmedLineFinal = line.trim();
              if (trimmedLineFinal.startsWith("data:")) finalContent += trimmedLineFinal.substring(5);
            });
            if (finalContent) updateAiMessageWithStreamData(finalContent);
            accumulatedChunk = '';
          }
          break;
        }
      } catch (readError: any) {
        if (readError.name === 'AbortError') {
          if (!streamError.value) streamError.value = '数据流读取中止';
        } else {
          if (!streamError.value) streamError.value = `读取数据流时发生错误: ${readError.message}`;
        }
        caughtErrorDuringStream = readError;
        doneReadingStream = true;
        break;
      }
    }
    if(decoder.decode()){} // Ensure final chunk is processed if any
  } catch (err: any) {
    caughtErrorDuringStream = err;
    if (err.name === 'AbortError') {
      if (!streamError.value) streamError.value = '请求已中止';
    } else {
      if (!streamError.value) streamError.value = `连接或处理错误: ${err.message || '未知错误'}`;
    }
  } finally {
    const wasActuallyStreaming = isStreaming.value;
    isStreaming.value = false;

    if (abortController.value && !abortController.value.signal.aborted) {
      abortController.value.abort();
    }
    abortController.value = null;

    const currentErrorState = streamError.value;

    if (currentErrorState && currentErrorState !== '用户主动终止对话') {
      if (currentAiMessageId) {
        updateFinalAiMessageWithStatus(currentErrorState, true);
      }
    } else if (!currentErrorState && wasActuallyStreaming && currentAiMessageId) {
      streamError.value = '对话正常结束';
    }
    scrollToBottom();
  }
};

const stopStreamUserAction = () => {
  if (isStreaming.value) {
    streamError.value = '用户主动终止对话';
    if (abortController.value) {
      abortController.value.abort();
    }
  }
};

const toggleStream = () => {
  if (isStreaming.value) {
    stopStreamUserAction();
  } else {
    startStream();
  }
};

watch(modelSel, (newValue) => { emit('modelChanged', newValue); });
watch(chatMessages, scrollToBottom, {deep: true});

onMounted(() => {
  // syncInputButtonHeight function removed as it's no longer needed for this layout
});
onUnmounted(() => {
  // window.removeEventListener('resize', syncInputButtonHeight); // Removed
  if (isStreaming.value || abortController.value) {
    if (!streamError.value) {
      streamError.value = '组件卸载，对话中止';
    }
    if (abortController.value && !abortController.value.signal.aborted) {
      abortController.value.abort();
    }
    isStreaming.value = false;

    if (currentAiMessageId && streamError.value === '组件卸载，对话中止') {
      const aiMessageEntry = chatMessages.value.find(m => m.id === currentAiMessageId);
      let hasFinalStatus = false;
      if(aiMessageEntry && aiMessageEntry.content){
        const content = aiMessageEntry.content;
        if(content.endsWith(']') && content.includes('[')){
          hasFinalStatus = true;
        }
      }
      if (aiMessageEntry && !hasFinalStatus) {
        updateFinalAiMessageWithStatus(streamError.value, true);
      }
    }
    abortController.value = null;
  }
});

const closePanel = () => { emit('close'); };

</script>


<style scoped>
/* (所有原有CSS样式保持不变，仅在末尾添加或修改) */
.panel {
  position: relative;
  background-color: #f0f2f5;
  border-left: 1px solid #dcdfe6;
  transition: width 0.3s ease;
  overflow: hidden;
  flex-shrink: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  /* width: 350px;  */
  min-width: 400px;
}

.ai-header {
  padding: 15px;
  font-size: 16px;
  font-weight: bold;
  border-bottom: 1px solid #ddd;
  flex-shrink: 0;
  background-color: #fff;
}

.ai-chat {
  flex: 1;
  padding: 15px;
  overflow-y: auto;
  min-height: 0;
  background-color: #fff;
}

.chat-message-wrapper {
  margin-bottom: 10px;
}

.chat-message {
  padding: 8px 12px;
  border-radius: 6px;
  word-wrap: break-word;
  white-space: pre-wrap;
}

.message-user {
  background-color: #d1e7dd;
  text-align: right;
  margin-left: auto;
  max-width: 80%;
}

.message-user .message-content {
  text-align: left;
}

.message-ai {
  background-color: #f8f9fa;
  border: 1px solid #e9ecef;
  max-width: 80%;
}

.message-content {
  margin: 0;
  font-family: inherit;
  font-size: 0.95em;
  line-height: 1.6;
  white-space: pre-wrap !important;
  overflow-wrap: break-word;
  word-break: break-all;
}

.panel-content {
  flex-shrink: 0;
  padding: 10px 15px;
  height: auto;
  border-top: 1px solid #ddd;
  background-color: #f0f2f5;
}

.ai-input-new {
  display: flex;
  align-items: flex-end; /* Aligns children (select, textarea, button-group) to the bottom */
  background-color: #ffffff;
  border: 1px solid #dcdfe6;
  border-radius: 8px;
  padding: 5px 8px;
  min-height: 42px; /* Will be overridden if content (like buttons) is taller */
  height: auto;
  box-sizing: border-box;
}

.input-prefix-area {
  margin-right: 8px;
  display: flex;
  align-items: center; /* Vertically center content within prefix area if needed */
  /* align-self: flex-end; is implicit due to parent's align-items: flex-end */
}

.compact-model-select {
  width: auto;
  min-width: 80px;
}

.compact-model-select .el-input__wrapper {
  box-shadow: none !important;
  height: 30px;
  padding: 0 8px;
  background-color: #f5f5f5;
  border-radius: 4px !important;
}
.compact-model-select .el-input__inner {
  height: 28px;
  line-height: 28px;
  font-size: 13px;
}
.compact-model-select .el-input__suffix {
  display: flex;
  align-items: center;
}


.main-chat-input {
  flex-grow: 1; /* Textarea takes available horizontal space */
}

.main-chat-input .el-input__wrapper {
  box-shadow: none !important;
  background-color: transparent !important;
  padding: 0 8px !important;
  border-radius: 0;
  display: flex;
  align-items: stretch;
}
.main-chat-input .el-input__inner {
  border: none !important;
  font-size: 14px;
  line-height: normal;
}

.main-chat-input.el-textarea .el-textarea__inner {
  box-shadow: none !important;
  background-color: transparent !important;
  padding: 2px 0px !important;
  border: none !important;
  font-size: 14px;
  line-height: 1.5;
  border-radius: 0;
  resize: none;
  min-height: 21px; /* Approx height for 1 row */
}

/* --- MODIFIED FOR VERTICAL BUTTONS --- */
.input-actions-suffix {
  display: flex;
  flex-direction: column; /* Stack buttons vertically */
  justify-content: flex-start; /* Align buttons to the top of this container */
  margin-left: 8px; /* Space between textarea and buttons */
  /* align-self: flex-end; is implicit due to parent's align-items: flex-end */
}

.input-actions-suffix .action-button:not(:last-child) {
  margin-bottom: 4px; /* Space between the two vertical buttons */
}
/* --- END MODIFIED FOR VERTICAL BUTTONS --- */

.action-button {
  background-color: transparent;
  border: none;
  padding: 5px; /* Padding inside the button */
  cursor: pointer;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #606266;
  transition: background-color 0.2s ease, color 0.2s ease;
  height: 30px; /* Fixed height for buttons */
  width: 30px;  /* Fixed width for buttons */
  box-sizing: border-box;
}

.action-button:hover {
  background-color: #ecf5ff;
  color: #409eff;
}

.action-button:active {
  background-color: #d9ecff;
}

.action-button svg {
  width: 18px;
  height: 18px;
}
.action-button span {
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  width: 100%;
  height: 100%;
}


.send-button.streaming {
  background-color: #f56c6c;
  color: white;
}
.send-button.streaming:hover {
  background-color: #f78989;
}

.stream-error-message {
  color: #ff4d4f;
  margin-top: 10px;
  padding: 8px 12px;
  background-color: rgba(255, 77, 79, 0.08);
  border: 1px solid rgba(255, 77, 79, 0.25);
  border-radius: 4px;
  font-size: 0.9em;
  word-break: break-all;
}

.user-stopped-prompt-yellow {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 10px;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 0.9em;
  background-color: #fffbe6;
  border: 1px solid #ffe58f;
  color: #d48806;
}

.user-stopped-prompt-yellow span {
  color: #bfbfbf;
}

.user-stopped-prompt-yellow .adopt-current-button {
  background-color: #ffd666;
  color: rgba(0, 0, 0, 0.85);
  border: 1px solid #ffc53d;
  padding: 4px 12px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.9em;
  margin-left: 10px;
  transition: background-color 0.2s ease, border-color 0.2s ease;
  font-weight: normal;
}

.user-stopped-prompt-yellow .adopt-current-button:hover {
  background-color: #ffc53d;
  border-color: #ffb000;
}
</style>
